using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OrchardCore.Data.EFCore;
using OrchardCore.Data.EFCore.Options;
using OrchardCore.Environment.Shell;
using OrchardCore.Data;

namespace OrchardCore.Data.EFCore;

/// <summary>
/// EF Core数据库连接验证器实现
/// 验证EF Core数据库连接的有效性和状态
/// </summary>
public class EFCoreConnectionValidator : IEFCoreConnectionValidator
{
    private readonly IEnumerable<DatabaseProvider> _databaseProviders;
    private readonly ILogger<EFCoreConnectionValidator> _logger;
    private readonly EFCoreOptions _efCoreOptions;

    public EFCoreConnectionValidator(
        IEnumerable<DatabaseProvider> databaseProviders,
        IOptions<EFCoreOptions> efCoreOptions,
        ILogger<EFCoreConnectionValidator> logger)
    {
        _databaseProviders = databaseProviders;
        _efCoreOptions = efCoreOptions.Value;
        _logger = logger;
    }

    public async Task<EFCoreConnectionValidatorResult> ValidateAsync(EFCoreConnectionValidatorContext context)
    {
        ArgumentNullException.ThrowIfNull(context);

        if (string.IsNullOrWhiteSpace(context.DatabaseProvider))
        {
            return EFCoreConnectionValidatorResult.EFNoProvider;
        }

        var provider = _databaseProviders.FirstOrDefault(p => p.Value == context.DatabaseProvider);
        if (provider == null)
        {
            return EFCoreConnectionValidatorResult.EFUnsupportedProvider;
        }

        var connectionString = context.ConnectionString;
        if (!provider.HasConnectionString)
        {
            if (provider.Value != DatabaseProviderValue.Sqlite)
            {
                return EFCoreConnectionValidatorResult.EFDocumentTableNotFound;
            }

            // 对于SQLite，生成默认连接字符串
            connectionString = "Data Source=Orchard.db";
        }

        if (string.IsNullOrWhiteSpace(connectionString))
        {
            return EFCoreConnectionValidatorResult.EFInvalidConnection;
        }

        try
        {
            // 创建DbContext选项
            var optionsBuilder = new DbContextOptionsBuilder();
            ConfigureDbContextByProvider(optionsBuilder, context.DatabaseProvider, connectionString);
            ApplyCommonConfiguration(optionsBuilder);

            // 创建DbContext实例进行测试
            using var dbContext = CreateDbContext(context.DbContextType, optionsBuilder.Options);
            
            // 测试连接
            if (!await dbContext.Database.CanConnectAsync())
            {
                return EFCoreConnectionValidatorResult.EFInvalidConnection;
            }

            // 检查是否需要迁移
            var pendingMigrations = await dbContext.Database.GetPendingMigrationsAsync();
            if (pendingMigrations.Any())
            {
                return EFCoreConnectionValidatorResult.EFMigrationRequired;
            }

            // 检查Document表是否存在
            var documentTableExists = await CheckDocumentTableExistsAsync(dbContext);
            if (!documentTableExists)
            {
                return EFCoreConnectionValidatorResult.EFDocumentTableNotFound;
            }

            return EFCoreConnectionValidatorResult.EFDocumentTableFound;
        }
        catch (Exception ex)
        {
            _logger.LogWarning(ex, "Failed to validate EF Core connection for provider: {Provider}", context.DatabaseProvider);
            return EFCoreConnectionValidatorResult.EFInvalidConnection;
        }
    }

    /// <summary>
    /// 根据数据库提供程序配置DbContext
    /// </summary>
    private static void ConfigureDbContextByProvider(DbContextOptionsBuilder optionsBuilder, string provider, string connectionString)
    {
        switch (provider)
        {
            case DatabaseProviderValue.SqlConnection:
                optionsBuilder.UseSqlServer(connectionString, sqlOptions =>
                {
                    // 移除 CommandTimeout 配置
                    sqlOptions.EnableRetryOnFailure();
                });
                break;

            case DatabaseProviderValue.Sqlite:
                optionsBuilder.UseSqlite(connectionString, sqlOptions =>
                {
                    // 移除 CommandTimeout 配置
                });
                break;

            case DatabaseProviderValue.MySql:
                optionsBuilder.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString), sqlOptions =>
                {
                    // 移除 CommandTimeout 配置
                    sqlOptions.EnableRetryOnFailure();
                });
                break;

            case DatabaseProviderValue.Postgres:
                optionsBuilder.UseNpgsql(connectionString, sqlOptions =>
                {
                    // 移除 CommandTimeout 配置
                    sqlOptions.EnableRetryOnFailure();
                });
                break;

            default:
                throw new ArgumentException($"Unsupported database provider: {provider}");
        }
    }

    /// <summary>
    /// 应用通用配置
    /// </summary>
    private void ApplyCommonConfiguration(DbContextOptionsBuilder optionsBuilder)
    {
        if (_efCoreOptions.EnableDetailedErrors)
        {
            optionsBuilder.EnableDetailedErrors();
        }

        // 配置敏感数据日志
        if (_efCoreOptions.EnableSensitiveDataLogging)
        {
            optionsBuilder.EnableSensitiveDataLogging();
        }

        // 移除 EnableServiceProviderValidation 配置

        // 移除 UseMemoryCache 配置（需要额外的包）
    }

    /// <summary>
    /// 创建DbContext实例
    /// </summary>
    private static Microsoft.EntityFrameworkCore.DbContext CreateDbContext(Type contextType, DbContextOptions options)
    {
        return (Microsoft.EntityFrameworkCore.DbContext)Activator.CreateInstance(contextType, options);
    }

    /// <summary>
    /// 检查Document表是否存在
    /// </summary>
    private static async Task<bool> CheckDocumentTableExistsAsync(Microsoft.EntityFrameworkCore.DbContext dbContext)
    {
        try
        {
            // 尝试查询Document表
            var sql = "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'Document'";
            var count = await dbContext.Database.SqlQueryRaw<int>(sql).FirstOrDefaultAsync();
            return count > 0;
        }
        catch
        {
            // 如果查询失败，可能表不存在
            return false;
        }
    }
} 